/**
 ******************************************************************************
 * @file    dma.c
 * @author  hyseim software Team
 * @date    22-Mar-2024
 * @brief   This file provides all the dma functions.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2020 Hyseim. Co., Ltd.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "common.h"
#include "dma.h"

/** @addtogroup IM110GW_StdPeriph_Driver
 * @{
 */

/** @defgroup DMAC
 * @brief DMAC driver modules
 * @{
 */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup DMAC_Private_Functions
 * @{
 */

/**
 * @brief  Deinitializes the DMACx peripheral registers to their default reset values.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1
 * @return None
 */
// TODO
#if 0
void DMAC_DeInit(DMAC_TypeDef* DMACx)
{
    if (DMACx == DMAC0)
    {
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_DMAC0, ENABLE);
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_DMAC0, DISABLE);
    }
    else if (DMACx == DMAC2)
    {
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_DMAC2, ENABLE);
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_DMAC2, DISABLE);
    }
}
#endif

/**
 * @brief  Initializes the DMACx Channely according to the specified parameters in
 *         the DMAC_ChannelInitStruct structure.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  DMAC_ChannelInitStruct: pointer to a DMAC_ChannelInit_t structure that contains
 *         the configuration information for the specified DMACx Channely.
 * @return None
 */
void DMAC_ChannelInit(DMAC_t *DMACx, uint8_t DMAC_Channel, DMAC_ChannelInit_t *DMAC_ChannelInitStruct)
{
    DMACx->Chx[DMAC_Channel].CCR |= DMAC_ChannelInitStruct->DMAC_ChannelPriority |
                                    DMAC_ChannelInitStruct->DMAC_SrcBurstTransactionLength |
                                    DMAC_ChannelInitStruct->DMAC_DstTfrDataWidth |
                                    DMAC_ChannelInitStruct->DMAC_SrcTfrDataWidth |
                                    DMAC_ChannelInitStruct->DMAC_TransferDirection |
                                    DMAC_ChannelInitStruct->DMAC_SrcAddrInc |
                                    DMAC_ChannelInitStruct->DMAC_DstAddrInc |
                                    (DMAC_ChannelInitStruct->DMAC_SrcHardwareHandshakingInterfaceAssign << DMAC_CCR_CHx_SRC_REQ_SEL) |
                                    (DMAC_ChannelInitStruct->DMAC_DstHardwareHandshakingInterfaceAssign << DMAC_CCR_CHx_DST_REQ_SEL);

    if (ENABLE == DMAC_ChannelInitStruct->DMAC_Reload)
    {
        DMACx->Chx[DMAC_Channel].CCR |= DMAC_AutoReload_Enable;
    }
    else
    {
        DMACx->Chx[DMAC_Channel].CCR &= ~DMAC_AutoReload_Enable;
    }

    DMACx->Chx[DMAC_Channel].CTSR = DMAC_ChannelInitStruct->DMAC_BlockTransferSize;

    DMACx->Chx[DMAC_Channel].CSAR = DMAC_ChannelInitStruct->DMAC_SrcAddress;
    DMACx->Chx[DMAC_Channel].CDAR = DMAC_ChannelInitStruct->DMAC_DstAddress;

    DMA_PRINT("Ch:%d CCR :0x%x\n", DMAC_Channel, DMACx->Chx[DMAC_Channel].CCR);
    DMA_PRINT("Ch:%d CTSR:0x%x\n", DMAC_Channel, DMACx->Chx[DMAC_Channel].CTSR);
    DMA_PRINT("Ch:%d CSAR:0x%x\n", DMAC_Channel, DMACx->Chx[DMAC_Channel].CSAR);
    DMA_PRINT("Ch:%d CDAR:0x%x\n", DMAC_Channel, DMACx->Chx[DMAC_Channel].CDAR);
}

/**
 * @brief  Fills each DMAC_ChannelInitStruct member with its default value.
 * @param  DMAC_ChannelInitStruct: pointer to a DMAC_ChannelInit_t structure which will
 *         be initialized.
 * @return None
 */
void DMAC_ChannelStructDefaultInit(DMAC_ChannelInit_t *DMAC_ChannelInitStruct)
{
    DMAC_ChannelInitStruct->DMAC_SrcAddress = 0x00000000;
    DMAC_ChannelInitStruct->DMAC_DstAddress = 0x00000000;

    DMAC_ChannelInitStruct->DMAC_DstTfrDataWidth = DMAC_DST_TFR_WIDTH_8bits;
    DMAC_ChannelInitStruct->DMAC_SrcTfrDataWidth = DMAC_SRC_TFR_WIDTH_8bits;
    DMAC_ChannelInitStruct->DMAC_DstAddrInc = DMAC_DstAddrInc_Increment;
    DMAC_ChannelInitStruct->DMAC_SrcAddrInc = DMAC_SrcAddrInc_Increment;
    DMAC_ChannelInitStruct->DMAC_SrcBurstTransactionLength = DMAC_SrcBurstTransactionLength_1;
    DMAC_ChannelInitStruct->DMAC_TransferDirection = DMAC_TransferDirection_M2M;
    DMAC_ChannelInitStruct->DMAC_BlockTransferSize = 1;

    DMAC_ChannelInitStruct->DMAC_SrcHardwareHandshakingInterfaceAssign = 0;
    DMAC_ChannelInitStruct->DMAC_DstHardwareHandshakingInterfaceAssign = 0;
    DMAC_ChannelInitStruct->DMAC_ChannelPriority = 0;

    DMAC_ChannelInitStruct->DMAC_Reload = DISABLE;
}

/**
 * @brief  Sets the source address of the specified DMACx Channely.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  SourceAddress: specifies the source address of the specified DMACx Channely.
 * @return None
 */
void DMAC_ChannelSetSourceAddress(DMAC_t *DMACx, uint8_t DMAC_Channel, uint32_t SourceAddress)
{
    DMACx->Chx[DMAC_Channel].CSAR = SourceAddress;
}

/**
 * @brief  Sets the destination address of the specified DMACx Channely.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  DestinationAddress: specifies the destination address of the specified DMACx Channely.
 * @return None
 */
void DMAC_ChannelSetDestinationAddress(DMAC_t *DMACx, uint8_t DMAC_Channel, uint32_t DestinationAddress)
{
    DMACx->Chx[DMAC_Channel].CDAR = DestinationAddress;
}

/**
 * @brief  Sets the number of data units to be transferred on the block transfer.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  DMAC_BlockTransferSize: specifies the number of data units to be transferred on the block transfer.
 *         This parameter can be a number between 1 and 0xffffffff..
 * @return None
 */
void DMAC_ChannelSetBlockTransferSize(DMAC_t *DMACx, uint8_t DMAC_Channel, uint32_t DMAC_BlockTransferSize)
{
    DMACx->Chx[DMAC_Channel].CTSR = DMAC_BlockTransferSize;
}

/**
 * @brief  Returns the number of remaining data in the current DMACx Channely block transfer.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @return The number of remaining data in the current DMACx Channely block transfer.
 */
uint32_t DMAC_ChannelGetBlockTransferSize(DMAC_t *DMACx, uint8_t DMAC_Channel)
{
    return (uint32_t)(DMACx->Chx[DMAC_Channel].CTSR);
}

/**
 * @brief  Forces or releases the current DMACx Channely transfer suspend.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  NewState: new state of the current DMACx Channely transfer suspend.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void DMAC_ChannelAbortCmd(DMAC_t *DMACx, uint8_t DMAC_Channel, FunctionalState_t NewState)
{
    if (NewState == ENABLE)
    {
        DMACx->ABT |= BIT(DMAC_Channel);
    }
    else
    {
        DMACx->ABT &= ~(BIT(DMAC_Channel));
    }
}

/**
 * @brief  Enables or disables the specified DMACx Channely.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be a combination of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  NewState: new state of the DMACx Channely.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void DMAC_ChannelCmd(DMAC_t *DMACx, uint8_t DMAC_Channel, FunctionalState_t NewState)
{
    if (NewState == ENABLE)
    {
        DMACx->Chx[DMAC_Channel].CCR |= DMAC_CCR_CHx_ENALBE;
    }
    else
    {
        DMACx->Chx[DMAC_Channel].CCR &= ~DMAC_CCR_CHx_ENALBE;
    }
}

// TODO Fixed in the next version
/**
 * @brief  Enables or disables the specified DMACx Channely for Reload mode.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be a combination of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  NewState: new state of the DMACx Channely.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void DMAC_ChannelCmdWithReload(DMAC_t *DMACx, uint8_t DMAC_Channel, FunctionalState_t NewState)
{
    if (NewState == ENABLE)
    {
        DMACx->Chx[DMAC_Channel].CCR |= DMAC_AutoReload_Enable | DMAC_CCR_CHx_ENALBE;
    }
    else
    {
        DMACx->Chx[DMAC_Channel].CCR &= ~DMAC_CCR_CHx_ENALBE;
        DMACx->Chx[DMAC_Channel].CCR |= DMAC_AutoReload_Enable;
    }
}

/**
 * @brief  Returns the status of EN bit for the specified DMACx Channely.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @return Current state of the DMACx Channely (ENABLE or DISABLE).
 */
FunctionalState_t DMAC_GetChannelCmdStatus(DMAC_t *DMACx, uint8_t DMAC_Channel)
{
    uint32_t mask = (uint32_t)(BIT(DMAC_Channel));
    FunctionalState_t state = DISABLE;

    if (0 != (DMACx->CESR & mask))
    {
        state = ENABLE;
    }
    else
    {
        state = DISABLE;
    }
    return state;
}

/**
 * @brief  Enables or disables the specified DMACx Channely interrupts.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be a combination of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  DMAC_IT: specifies the DMAC interrupt source to be enabled or disabled.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_IT_TFR_TRIG: Transfer complete interrupt.
 *         @arg @ref DMAC_IT_ERR_TRIG: Block complete interrupt.
 *         @arg @ref DMAC_IT_ABT_TRIG: Source transaction complete interrupt.
 * @param  NewState: new state of the specified DMAC interrupt.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None.
 */
void DMAC_ITConfig(DMAC_t *DMACx, uint8_t DMAC_Channel, uint8_t DMAC_IT, FunctionalState_t NewState)
{
    if (NewState == ENABLE)
    {
        /* Enable the selected DMAC interrupt */
        DMACx->Chx[DMAC_Channel].CCR &= ~(BIT(DMAC_IT));
    }
    else
    {
        /* Disable the selected DMAC interrupt */
        DMACx->Chx[DMAC_Channel].CCR |= BIT(DMAC_IT);
    }
}

// TODO Fixed in the next version
/**
 * @brief  Enables or disables the specified DMACx Channely interrupts for Reload mode
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be a combination of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  DMAC_IT: specifies the DMAC interrupt source to be enabled or disabled.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_IT_TFR_TRIG: Transfer complete interrupt.
 *         @arg @ref DMAC_IT_ERR_TRIG: Block complete interrupt.
 *         @arg @ref DMAC_IT_ABT_TRIG: Source transaction complete interrupt.
 * @param  NewState: new state of the specified DMAC interrupt.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None.
 */
void DMAC_ITConfigWithReload(DMAC_t *DMACx, uint8_t DMAC_Channel, uint8_t DMAC_IT, FunctionalState_t NewState)
{
    if (NewState == ENABLE)
    {
        /* Enable the selected DMAC interrupt */
        DMACx->Chx[DMAC_Channel].CCR &= ~(BIT(DMAC_IT));
        DMACx->Chx[DMAC_Channel].CCR |= DMAC_AutoReload_Enable;
    }
    else
    {
        /* Disable the selected DMAC interrupt */
        DMACx->Chx[DMAC_Channel].CCR |= BIT(DMAC_IT);
        DMACx->Chx[DMAC_Channel].CCR |= DMAC_AutoReload_Enable;
    }
}

/**
 * @brief  Checks whether the specified DMACx Channely interrupt has occurred or not.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  DMAC_IT: specifies the DMAC interrupt source to check.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_IT_TFR_ISR: Transfer complete interrupt flag.
 *         @arg @ref DMAC_IT_ABT_ISR: Block complete interrupt flag.
 *         @arg @ref DMAC_IT_ERR_ISR: Source transaction complete interrupt flag.
 * @return The new state of DMAC_IT (SET or RESET).
 */
ITStatus_t DMAC_GetITStatus(DMAC_t *DMACx, uint8_t DMAC_Channel, uint8_t DMAC_IT)
{
    uint32_t mask = (uint32_t)(BIT(DMAC_Channel + DMAC_IT));
    ITStatus_t bitstatus = RESET;

    if (im_read32(&DMACx->ISR) & mask)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }
    return bitstatus;
}

/**
 * @brief  Clear the specified DMACx Channely interrupts.
 * @param  DMACx: Pointer to selected DMAC peripheral.
 *         This parameter can be one of the following values:
 *         DMAC1.
 * @param  DMAC_Channel: specifies the selected DMAC channel.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_Channel_0
 *         @arg @ref DMAC_Channel_1
 *         @arg @ref DMAC_Channel_2
 *         @arg @ref DMAC_Channel_3
 *         @arg @ref DMAC_Channel_4
 *         @arg @ref DMAC_Channel_5
 *         @arg @ref DMAC_Channel_6
 *         @arg @ref DMAC_Channel_7
 * @param  DMAC_IT: specifies the DMAC interrupt source.
 *         This parameter can be one of the following values:
 *         @arg @ref DMAC_IT_TFR_ISR: Transfer complete interrupt flag.
 *         @arg @ref DMAC_IT_ABT_ISR: Block complete interrupt flag.
 *         @arg @ref DMAC_IT_ERR_ISR: Source transaction complete interrupt flag.
 * @return None.
 */
void DMAC_ClearITBit(DMAC_t *DMACx, uint8_t DMAC_Channel, uint8_t DMAC_IT)
{
    DMACx->ISR = BIT(DMAC_Channel + DMAC_IT);
}

/**
 * @brief  DMA handshaking interface signal mux.
 * @return None.
 */
void DMAC_InitHardwareHandshakingInterfaceMux(void)
{
    im_write32((SCU_BASE + ADDR_CFG_SOC_CON4), 0xFFFFFFFF);
    im_write32((SCU_BASE + ADDR_CFG_SOC_CON5), 0xFFFFFFFF);
    im_write32((SCU_BASE + ADDR_CFG_SOC_CON6), 0xFFFFFFFF);
    im_write32((SCU_BASE + ADDR_CFG_SOC_CON7), 0xFFFFFFFF);
}

/**
 * @brief  Get an available hardware handshake number.
 * @param  HardwareHandshakingInterface: DMAC_HardwareHandshakingInterface
 *         This parameter can be one of the following values:
 *         @arg @ref DMA_HS_ASSI0_DMA_TX     (0U)
 *         @arg @ref DMA_HS_ASSI0_DMA_RX     (1U)
 *         @arg @ref DMA_HS_UART1_DMA_TX     (2U)
 *         @arg @ref DMA_HS_UART1_DMA_RX     (3U)
 *         @arg @ref DMA_HS_ASSI2_DMA_TX     (4U)
 *         @arg @ref DMA_HS_ASSI2_DMA_RX     (5U)
 *         @arg @ref DMA_HS_ASSI3_DMA_TX     (6U)
 *         @arg @ref DMA_HS_ASSI3_DMA_RX     (7U)
 *         @arg @ref DMA_HS_ASSI4_DMA_TX     (8U)
 *         @arg @ref DMA_HS_ASSI4_DMA_RX     (9U)
 *         @arg @ref DMA_HS_ASSI5_DMA_TX     (10U)
 *         @arg @ref DMA_HS_ASSI5_DMA_RX     (11U)
 *         @arg @ref DMA_HS_ASSI6_DMA_TX     (12U)
 *         @arg @ref DMA_HS_ASSI6_DMA_RX     (13U)
 *         @arg @ref DMA_HS_ASSI7_DMA_TX     (14U)
 *         @arg @ref DMA_HS_ASSI7_DMA_RX     (15U)
 *         @arg @ref DMA_HS_TRIG_DMAMUX0     (16U)
 *         @arg @ref DMA_HS_TRIG_DMAMUX1     (17U)
 *         @arg @ref DMA_HS_TRIG_DMAMUX2     (18U)
 *         @arg @ref DMA_HS_TRIG_DMAMUX3     (19U)
 * @return success: 0-15
 *         failed : 0xFF
 */
uint8_t DMAC_GetHardwareHandshakeNumber(uint8_t HardwareHandshakingInterface)
{
    uint32_t regadd = SCU_BASE + ADDR_CFG_SOC_CON4;
    uint8_t i;
    uint8_t j = -1;

    uint32_t tmp;
    uint8_t m;
    for (i = 0; i < HANDSHAKING_MAX_NUM; i += 4)
    {
        tmp = im_read32(regadd + i);
        for (size_t k = 0; k < 32; k += 8)
        {
            j++;
            if (0xFF == ((tmp >> k) & 0xFF))
            {
                if (j < HANDSHAKING_MAX_NUM)
                {
                    tmp &= ~(0xFF << k);
                    im_write32((regadd + i), ((HardwareHandshakingInterface << k) | tmp));
                    for (m = 0; m < HANDSHAKING_MAX_NUM; m += 4)
                    {
                        DMA_PRINT("1->redadd:0x%x\tdata:0x%x\n", regadd + m, im_read32(regadd + m));
                    }
                    DMA_PRINT("\n");
                    return j;
                }
            }
        }
    }
    return 0xFF;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
/*******************(C)COPYRIGHT 2020 Hyseim ***********END OF FILE************/